/******************************************************************************
 * Copyright 2022 The AIR Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#pragma once

#include <string>

#include "cw/key-pair.hpp"
namespace cw {
class AsymCipher {
  using func_ctx_init_t = int (*)(EVP_PKEY_CTX *);

  using func_sign_t = int (*)(EVP_PKEY_CTX *,             // [IN]  context
                              unsigned char *, size_t *,  // [OUT] Signature
                              const unsigned char *,
                              size_t);           // [IN]  To be signed
  using func_verify_t = int (*)(EVP_PKEY_CTX *,  // [IN] context
                                const unsigned char *,
                                size_t,  // [IN] Signature
                                const unsigned char *,
                                size_t);          // [IN] To be signed
  using func_encrypt_t = int (*)(EVP_PKEY_CTX *,  // [IN]  context
                                 unsigned char *, size_t *,  // [OUT] Encrypted
                                 const unsigned char *, size_t);  // [IN]  Data
  using func_decrypt_t = int (*)(EVP_PKEY_CTX *,             // [IN]  context
                                 unsigned char *, size_t *,  // [OUT] Decrypted
                                 const unsigned char *, size_t);  // [IN]  Data

  const KeyPair kp_;
  const EVP_PKEY_METHOD *meth_{nullptr};

  func_ctx_init_t func_sign_init_{EVP_PKEY_sign_init};
  func_ctx_init_t func_verify_init_{EVP_PKEY_verify_init};
  func_ctx_init_t func_encrypt_init_{EVP_PKEY_encrypt_init};
  func_ctx_init_t func_decrypt_init_{EVP_PKEY_decrypt_init};

  func_sign_t func_sign_{EVP_PKEY_sign};
  func_verify_t func_verify_{EVP_PKEY_verify};
  func_encrypt_t func_encrypt_{EVP_PKEY_encrypt};
  func_decrypt_t func_decrypt_{EVP_PKEY_decrypt};

 public:
  explicit AsymCipher(KeyPair kp, int meth_type = NID_undef);

  std::string Encipher(const std::string &data) const;
  std::string Decipher(const std::string &data) const;
  std::string Sign(const std::string &data) const;
  bool Verify(const std::string &data, const std::string &signature) const;
};

}  // namespace cw
#include "impl/asym-cipher-impl.hpp"
